/**
 * 日志服务
 * 作者：GodMainCode
 * 创建时间：2024-01-17
 * 修改时间：2024-01-17
 * 修改人：GodMainCode
 */

import { Injectable, Logger } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { Repository, Between, LessThanOrEqual } from 'typeorm';
import { Log } from './entities/log.entity';
import { LogType, LogLevel, ILogQuery } from '../../interfaces/log.interface';
import { Request } from 'express';
import { LogStatsDto } from './dto/log-stats.dto';
import * as moment from 'moment';

@Injectable()
export class LogService {
  private readonly logger = new Logger(LogService.name);

  constructor(
    @InjectRepository(Log)
    private readonly logRepository: Repository<Log>,
  ) {}

  /**
   * 创建日志
   * @param type 日志类型
   * @param level 日志级别
   * @param request 请求对象
   * @param duration 执行时长
   * @param result 操作结果
   * @param error 错误信息
   */
  async create(
    type: LogType,
    level: LogLevel,
    request: Request,
    duration: number,
    result?: string,
    error?: string,
  ): Promise<void> {
    const user = request.user as any;
    const log = this.logRepository.create({
      type,
      level,
      user_id: user?.id,
      username: user?.username,
      ip: request.ip,
      method: request.method,
      path: request.url,
      params: JSON.stringify(request.body),
      result,
      error,
      duration,
      user_agent: request.headers['user-agent'],
    });

    await this.logRepository.save(log);
  }

  /**
   * 查询日志
   * @param query 查询条件
   * @returns Promise<[Log[], number]> 日志列表和总数
   */
  async findAll(query: ILogQuery): Promise<[Log[], number]> {
    const { type, level, username, ip, startTime, endTime, page = 1, pageSize = 10 } = query;

    const queryBuilder = this.logRepository.createQueryBuilder('log');

    if (type) {
      queryBuilder.andWhere('log.type = :type', { type });
    }

    if (level) {
      queryBuilder.andWhere('log.level = :level', { level });
    }

    if (username) {
      queryBuilder.andWhere('log.username LIKE :username', { username: `%${username}%` });
    }

    if (ip) {
      queryBuilder.andWhere('log.ip = :ip', { ip });
    }

    if (startTime && endTime) {
      queryBuilder.andWhere({
        created_at: Between(startTime, endTime),
      });
    }

    queryBuilder
      .orderBy('log.created_at', 'DESC')
      .skip((page - 1) * pageSize)
      .take(pageSize);

    return await queryBuilder.getManyAndCount();
  }

  /**
   * 清理日志
   * @param days 保留天数
   */
  async clean(days: number): Promise<void> {
    const date = new Date();
    date.setDate(date.getDate() - days);

    await this.logRepository
      .createQueryBuilder()
      .delete()
      .where('created_at < :date', { date })
      .execute();
  }

  /**
   * 获取日志统计信息
   * @returns Promise<LogStatsDto> 日志统计信息
   */
  async getStats(): Promise<LogStatsDto> {
    const now = new Date();
    const startOfToday = moment().startOf('day').toDate();
    const startOfWeek = moment().startOf('week').toDate();
    const startOfMonth = moment().startOf('month').toDate();

    const [
      total,
      operationLogs,
      loginLogs,
      errorLogs,
      debugLogs,
      infoLogs,
      warnLogs,
      todayLogs,
      weekLogs,
      monthLogs,
    ] = await Promise.all([
      this.logRepository.count(),
      this.logRepository.count({ where: { type: LogType.OPERATION } }),
      this.logRepository.count({ where: { type: LogType.LOGIN } }),
      this.logRepository.count({ where: { type: LogType.ERROR } }),
      this.logRepository.count({ where: { level: LogLevel.DEBUG } }),
      this.logRepository.count({ where: { level: LogLevel.INFO } }),
      this.logRepository.count({ where: { level: LogLevel.WARN } }),
      this.logRepository.count({
        where: { created_at: Between(startOfToday, now) },
      }),
      this.logRepository.count({
        where: { created_at: Between(startOfWeek, now) },
      }),
      this.logRepository.count({
        where: { created_at: Between(startOfMonth, now) },
      }),
    ]);

    return {
      total,
      byType: {
        [LogType.OPERATION]: operationLogs,
        [LogType.LOGIN]: loginLogs,
        [LogType.ERROR]: errorLogs,
      },
      byLevel: {
        [LogLevel.DEBUG]: debugLogs,
        [LogLevel.INFO]: infoLogs,
        [LogLevel.WARN]: warnLogs,
        [LogLevel.ERROR]: errorLogs,
      },
      today: todayLogs,
      thisWeek: weekLogs,
      thisMonth: monthLogs,
      errors: errorLogs,
    };
  }

  /**
   * 获取日志趋势数据
   * @param days 天数
   * @returns Promise<{ date: string; count: number }[]> 日志趋势数据
   */
  async getTrend(days: number = 7): Promise<{ date: string; count: number }[]> {
    const startDate = moment().subtract(days - 1, 'days').startOf('day').toDate();
    const endDate = moment().endOf('day').toDate();

    const logs = await this.logRepository
      .createQueryBuilder('log')
      .select('DATE(created_at)', 'date')
      .addSelect('COUNT(*)', 'count')
      .where('created_at BETWEEN :startDate AND :endDate', {
        startDate,
        endDate,
      })
      .groupBy('DATE(created_at)')
      .getRawMany();

    // 填充没有数据的日期
    const trend: { date: string; count: number }[] = [];
    for (let i = 0; i < days; i++) {
      const date = moment(startDate).add(i, 'days').format('YYYY-MM-DD');
      const logData = logs.find(log => log.date === date);
      trend.push({
        date,
        count: logData ? parseInt(logData.count) : 0,
      });
    }

    return trend;
  }
} 